#!/usr/bin/env python
# Author: Diana Godfrey, Denis Gorbunov, Jonathan Schultz

PKG = 'languagememory'

import roslib; roslib.load_manifest(PKG)
import rospy
import re
import personMem
import traceback

from threading import Thread, Lock, RLock, Condition

from conversation.msg import PersonEvent
from facel.srv import *
from std_msgs.msg import String
from festival.srv import *
from nltk_parser.srv import *
from nltk_interpret.srv import *

class MeetGreetDemo():

    listNames = []
    question = "your name"

    def __init__(self):
        rospy.init_node('meet_greet_demo_node', anonymous=True)

        self.name = "unknown"
        self.personDict = dict()
        self.personDict[self.name] = "WAITING"
        self.badAnswerCount = 0

        rospy.Subscriber("/person_event", PersonEvent, self.handle_person_event)
        rospy.Subscriber("/nltk_interpret", String, self.speech_callback)

        self.tts_pub = rospy.Publisher("tts", String)

        self.memory = personMem.PersonMemory()
        self.speechLock = Lock()
        self.namingLock = Lock()
        self.talkLock = Lock()        

        rospy.wait_for_service('speak_text')
        try:
            self.speak_text_service = rospy.ServiceProxy('speak_text', FestivalSpeech)
        except rospy.ServiceException, e:
            print "Failed to acquire Festival SpeakText service: %s"%e

        rospy.wait_for_service('nltk_interpret')
        try:
            self.parse_nltk = rospy.ServiceProxy('nltk_interpret', String)
        except rospy.ServiceException, e:
            print "nltk interpret failed: %s"%e

    def speak_text(self, text):
        with self.talkLock:
            #print "I AM SAYING (LOUDLY): " + text
            #print ">>>> CALLING FESTIVAL >>>>>"
            self.speak_text_service(text)
            #print "<<<< FESTIVAL RETURNED <<<<<<"

    def enrollFace(self, name):
        rospy.wait_for_service("enroll")
        try:
            enrollFace = rospy.ServiceProxy("enroll", Enroll)
            result = enrollFace(name)
            # Diana is adding this line 5/6 to change unknown back to WAITING so
            # when the next unknown person comes in the status will initially
            # be WAITING
            self.set_person_status("unknown", "WAITING")
            return result
        except rospy.ServiceException, e:
            print "Service call failed: %s"%e

    def trainFaces(self):
        rospy.wait_for_service("train")
        try:
            trainFaces = rospy.ServiceProxy("train", Train)
            result = trainFaces()
            return result
        except rospy.ServiceException, e:
            print "Service call failed: %s"%e

    def resetFaces(self):
        rospy.wait_for_service("reset")
        try:
            resetFaces = rospy.ServiceProxy("reset", Reset)
            result = resetFaces()
            return result
        except rospy.ServiceException, e:
            print "Service call failed: %s"%e

    def set_person_status(self, person, status):
        print "The old status of " + person + " is " + self.personDict[person]
        self.personDict[person] = status
        print "The new status of " + person + " is " + self.personDict[person]
        print self.personDict

    def get_person_status(self, person):
        return self.personDict[person]

    def handle_person_event(self, msg):
        with self.namingLock:

            name = msg.name
            event = msg.event
            state = "WAITING"
            
            if (name in self.personDict):
                state = self.get_person_status(name)

            print "When I was in state " + state + ", " + name + " " + event + "."

            if state == "WAITING":

                if event == "entered":
                    self.set_person_status(name, "TALKING")

                    if name == "unknown":
                        sentence = self.greet()
                    else:
                        sentence = self.greet(name)
                        
                    self.speak_text(sentence)                    
                    self.name = name
                    
            elif state == "TALKING":
                if event == "exited":
                    self.set_person_status(name, "WAITING")
                   # self.set_person_status("unknown", "TALKING")
                    if name == "unknown":
                        sentence = ("Bye")
                    else:
                        sentence = ("Bye, " + name + "!")
                    self.speak_text(sentence)

            print "After the PersonEvent, I am talking to " + self.name + ". I am " + self.personDict[self.name] + "."

    def greet(self, name=None):
        if name:
            self.question = "your major"
        else:
            self.question = "your name"

        return self.memory.introduce(name)
        #sentence = self.memory.introduce(name)
        #return self.speak_text(sentence)

    def speech_callback(self,text):
        with self.speechLock:
            print text.data
            split = text.data.split(':')
            self.command = split[0]
            self.quest = split[1]
            self.size = split[2]
            self.color = split[3]
            self.shape = split[4]
            self.topic = split[5]
            self.person = split[6]
            self.major = split[7]
            self.food = split[8]

            try:
                state = self.personDict[self.name]
            except:
                print "EXCEPTION: PERSON NOT FOUND: " + self.name
                state = "WAITING"
            print self.name + " is in state " + state

            if state == "WAITING":
                pass # might be return
                return

            try:
                quest = self.question
                response = None

                if quest == "your name":
                    if self.person != "":
                        response = self.respondName(self.person)
                    else:
                        response = self.wrongAnswer(quest)

                elif quest == "your major":
                    if self.major != "":
                        response = self.respondMajor(self.major)
                    else: response = self.wrongAnswer(quest)

                elif quest == "your favorite food":
                    if self.food != "":
                        response = self.respondFavFood(self.food)
                    else: response = self.wrongAnswer(quest)

                elif quest == "your food recommendation":
                    if self.food != "":
                        response = self.respondRecFood(self.food)
                        self.personDict[self.name] = "WAITING"
                    elif self.command != "":
                        response = self.respondRecFood(self.command)
                    else: response = self.wrongAnswer(quest)

                elif quest == "newFriend":
                    response = self.greet(self.name)

                else:
                    print "Did I even ask you a question?"

                if response:
                    self.speak_text(response)
                else:
                    self.speak_text("I'm not sure what you're talking about.")

            except Exception, e:
    ##            print "speech callback failed:"
    ##            traceback.print_exc()
                pass

    def wrongAnswer(self, quest):
        if self.badAnswerCount == 0:
            self.badAnswerCount += 1
            return "Huh?"
        
        answer = "that"
        if quest != "your name":
            if self.person != "":
                answer = self.person
        if quest != "your major":
            if self.major != "":
                answer = self.major
        if quest != "your favorite food" and quest != "your food recommendation":
            if self.food != "":
                answer = self.food
        self.badAnswerCount = 0
        return "Yeah. I don't think " + answer + " is really " + quest + ". Again, please."

    def respondName(self, name):
        with self.namingLock:
            self.question = "your major"
            
            print 'respondName'

            # The person is already known, but was not recognized (visually)
            if name in self.listNames:
                self.name = name
                response = self.memory.callMakeFriend(name)
                self.personDict[self.name] = "TALKING" # Do we need this?

            # The person's name is not known
            else:
                # Enroll the new person under their name
                self.listNames.append(name)
                self.name = name
                self.personDict[self.name] = "TALKING"
                self.speak_text("Please wait while I am learning your face. Thanks.")
                result = self.enrollFace(name)

                print "result=" + str(result)

                # Training, when there is more than one face
                if (len(self.listNames) >= 2):
                    self.speak_text("Almost done. Please wait a bit more. You don't need to stay still. Thanks.")
                    self.trainFaces()

                self.speak_text("Thanks for waiting, " + name + ". Let's talk now!")

                response = self.memory.callMakeFriend(name) + "          " + self.memory.askMajor()
            return response

    def respondMajor(self, major):
        self.question = "your favorite food"
        response = self.memory.respondMajor(major) + "          " + self.memory.askFood()
        return response

    def respondFavFood(self, food):
        self.question = "your food recommendation"
        weather = self.memory.talkWeather()
        response = self.memory.respondFood(food) + "          " + weather + "                         " + self.memory.talkFood()
        return response

    def respondRecFood(self, rec):
        self.question = "newFriend"
        response = self.memory.commentFood(rec) + "                             " + self.memory.askFriend()
        return response

if __name__ == '__main__':
    try:
        r = MeetGreetDemo()
        rospy.spin()
    except rospy.ROSInterruptException: pass
